#ifndef _TBSTRING2_H_
#define _TBSTRING2_H_

#include "TBSettings.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

namespace tb
{

	enum CompareMode
	{
		eCompareMode_CaseSensitive,
		eCompareMode_CaseInsensitive
	};

	template <typename C>
	class StringBase
	{

		friend class StringBase;
	
	public:
	
		StringBase();
		StringBase(int a_Maximum);
		StringBase(const char* a_String);
		StringBase(const char* a_String, int a_Maximum);
		StringBase(const wchar_t* a_String);
		StringBase(const wchar_t* a_String, int a_Maximum);
		StringBase(const StringBase<char>& a_Other);
		StringBase(const StringBase<wchar_t>& a_Other);
		~StringBase();

		TB_INLINE int GetLength() const { return m_Length; }
		TB_INLINE int GetMaximum() const { return m_Maximum; }

		// ================================
		// Access
		// ================================

		TB_INLINE C* GetData() { return m_Data; }
		TB_INLINE C* GetData() const { return m_Data; }

		// ================================
		// Functions
		// ================================

		StringBase<C>& Clear();
		StringBase<C>& Resize(int a_Maximum = -1);

		// ================================
		// Formatting
		// ================================

		StringBase<C>& Format(const char* a_Format, ...);
		StringBase<C>& Format(const wchar_t* a_Format, ...);

		// ================================
		// Substrings
		// ================================

		StringBase<C> GetSubLeft(int a_CharacterCount) const;
		StringBase<C> GetSubMiddle(int a_Start, int a_CharacterCount = -1) const;
		StringBase<C> GetSubRight(int a_CharacterCount) const;

		// ================================
		// Find
		// ================================

		int FindLeft(C a_Character, int a_Occurance = 1) const;
		int FindRight(C a_Character, int a_Occurance = 1) const;

		int FindNextLeft(C a_Character, int a_Start, int a_Occurance = 1) const;
		int FindNextRight(C a_Character, int a_Start, int a_Occurance = 1) const;

		StringBase<C> GetFindLeft(C a_Character, int a_Occurance = 1) const;
		StringBase<C> GetFindRight(C a_Character, int a_Occurance = 1) const;
		StringBase<C> GetFindMiddle(C a_Character, int a_Start, int a_Occurance = 1) const;

		// ================================
		// Copying
		// ================================

		StringBase<C>& Copy(const char* a_String, int a_CharacterCount = -1);
		StringBase<C>& Copy(const wchar_t* a_String, int a_CharacterCount = -1);

		// ================================
		// Pushing
		// ================================

		StringBase<C>& Push(char a_Character);
		StringBase<C>& Push(wchar_t a_Character);

		// ================================
		// Appending
		// ================================

		StringBase<C>& Append(const StringBase<char>& a_String);
		StringBase<C>& Append(const StringBase<wchar_t>& a_String);
		StringBase<C>& Append(const char* a_String);
		StringBase<C>& Append(const wchar_t* a_String);

		// ================================
		// Erasing
		// ================================

		StringBase<C>& EraseLeft(int a_Start, int a_CharacterCount = -1);
		StringBase<C>& EraseRight(int a_Start, int a_CharacterCount = -1);

		// ================================
		// Conversion
		// ================================

		//operator C* ();
		//operator const C* ();

		StringBase<C>& ToCharArray(char* a_Array, unsigned int a_Maximum);
		StringBase<C>& ToWideCharArray(wchar_t* a_Array, unsigned int a_Maximum);

		short ToShort(bool* a_Check = 0);
		unsigned short ToUShort(bool* a_Check = 0);
		long ToLong(bool* a_Check = 0);
		unsigned long ToULong(bool* a_Check = 0);
		float ToFloat(bool* a_Check = 0);
		double ToDouble(bool* a_Check = 0);

		// ================================
		// Operators
		// ================================

		C& operator [] (int a_Index);
		const C& operator [] (int a_Index) const;

		StringBase<C>& operator = (const StringBase<char>& a_String);
		StringBase<C>& operator = (const StringBase<wchar_t>& a_String);
		StringBase<C>& operator = (const char* a_String);
		StringBase<C>& operator = (const wchar_t* a_String);

		StringBase<C>& operator += (const StringBase<char>& a_String);
		StringBase<C>& operator += (const StringBase<wchar_t>& a_String);
		StringBase<C>& operator += (const char* a_String);
		StringBase<C>& operator += (const wchar_t* a_String);

		StringBase<C> operator + (const StringBase<char>& a_String) const;
		StringBase<C> operator + (const StringBase<wchar_t>& a_String) const;
		StringBase<C> operator + (const char* a_String) const;
		StringBase<C> operator + (const wchar_t* a_String) const;

		// ================================
		// Comparison
		// ================================

		bool IsEmpty() const;

		bool Compare(const char* a_String, CompareMode a_Mode = eCompareMode_CaseSensitive) const;
		bool Compare(const wchar_t* a_String, CompareMode a_Mode = eCompareMode_CaseSensitive) const;
		bool Compare(const StringBase<char>& a_String, CompareMode a_Mode = eCompareMode_CaseSensitive) const;
		bool Compare(const StringBase<wchar_t>& a_String, CompareMode a_Mode = eCompareMode_CaseSensitive) const;
		
	private:

		C* m_Data;
		int m_Length, m_Maximum;

		StringBase<C>& (StringBase::*_AppendSingle)(const char* a_String);
		StringBase<C>& (StringBase::*_AppendDouble)(const wchar_t* a_String);

		StringBase<C>& _AppendDynSingle(const char* a_String);
		StringBase<C>& _AppendFixedSingle(const char* a_String);
		StringBase<C>& _AppendDynDouble(const wchar_t* a_String);
		StringBase<C>& _AppendFixedDouble(const wchar_t* a_String);
	
	}; // class StringBase

	typedef StringBase<char> String;

	// ================================
	// Equality operator
	// ================================

	template <typename C> 
	bool operator == (const C* a_StringLeft, const StringBase<C>& a_StringRight);
	template <typename C>
	bool operator == (const StringBase<C>& a_StringLeft, const C* a_StringRight);
	template <typename C, typename D> 
	bool operator == (const C* a_StringLeft, const StringBase<D>& a_StringRight);
	template <typename C, typename D>
	bool operator == (const StringBase<C>& a_StringLeft, const D* a_StringRight);
	template <typename C, typename D>
	bool operator == (const StringBase<C>& a_StringLeft, const StringBase<D>& a_StringRight);

	// ================================
	// Inequality operator
	// ================================

	template <typename C> 
	bool operator != (const C* a_StringLeft, const StringBase<C>& a_StringRight);
	template <typename C>
	bool operator != (const StringBase<C>& a_StringLeft, const C* a_StringRight);
	template <typename C, typename D> 
	bool operator != (const C* a_StringLeft, const StringBase<D>& a_StringRight);
	template <typename C, typename D>
	bool operator != (const StringBase<C>& a_StringLeft, const D* a_StringRight);
	template <typename C, typename D>
	bool operator != (const StringBase<C>& a_StringLeft, const StringBase<D>& a_StringRight);

}; // namespace tb

#include "TBStringHelper.inl"
#include "TBString2.inl"
	
#endif
